package damas.modelo;

/**
 * @author Clace dedicada exclusiviamente a la IA del juego.
 *
 */
public class Heuristica {

	private static int ROJA = -3;
	private static int NEGRA = 3;
	private static int DAMA = 5;

	/**
	 * @param t
	 *            {@link int[][]}
	 * @param color
	 *            {@link int}
	 * @param misFichas
	 *            {@link int} Numero de fichas que tengo en el tablero de un
	 *            color determinado
	 * @return {@link int}
	 * 
	 *         cantidad de fichas que no pueden sercomidas por fichas enemigas.
	 *         Diferencia entre damas y fichas comunes
	 */
	public static int fichasASalvo(int[][] t, int color, int misFichas) {

		int salvos = misFichas;
		boolean aI, aD, abI, abD, aIE, aDE, abIE, abDE, aIED, aDED, abIED, abDED;
		boolean meComen;
		if (misFichas > 0) {

			if (esFichaRoja(color)) {

				for (int i = 1; i < 7; i++) {
					for (int j = 1; j < 7; j++) {

						meComen = false;
						// si la ficha es mia (roja)
						if (t[i][j] == color) {
							// vacios
							aI = t[i - 1][j - 1] == 0;
							aD = t[i - 1][j + 1] == 0;
							abI = t[i + 1][j - 1] == 0;
							abD = t[i + 1][j + 1] == 0;

							// enemiga (comun o dama)
							aIE = !esFichaRoja(t[i - 1][j - 1]) && !aI;
							aDE = !esFichaRoja(t[i - 1][j + 1]) && !aD;
							abIE = !esFichaRoja(t[i + 1][j - 1]) && !abI;
							abDE = !esFichaRoja(t[i + 1][j + 1]) && !abD;

							// enemiga dama
							aIED = t[i - 1][j - 1] == NEGRA * DAMA;
							aDED = t[i - 1][j + 1] == NEGRA * DAMA;

							// si alguna negra o dama negra la rodea ver que
							// pasa
							if (aDE || aIE || abIE || abDE) {
								if (aIED && abD)
									meComen = true;
								if (aDED && abI)
									meComen = true;
								if (abIE && aD)
									meComen = true;
								if (abDE && aI)
									meComen = true;
								if (meComen)
									salvos--;
							}
						}
					}
				}

				// NEGRAS
			} else {

				for (int i = 1; i < 7; i++) {
					for (int j = 1; j < 7; j++) {

						meComen = false;
						// si la ficha es mia (negra)
						if (t[i][j] == color) {
							// vacios
							aI = t[i - 1][j - 1] == 0;
							aD = t[i - 1][j + 1] == 0;
							abI = t[i + 1][j - 1] == 0;
							abD = t[i + 1][j + 1] == 0;

							// enemiga (comun o dama)
							aIE = esFichaRoja(t[i - 1][j - 1]);
							aDE = esFichaRoja(t[i - 1][j + 1]);
							abIE = esFichaRoja(t[i + 1][j - 1]);
							abDE = esFichaRoja(t[i + 1][j + 1]);

							// enemiga dama
							abIED = t[i + 1][j - 1] == ROJA * DAMA;
							abDED = t[i + 1][j + 1] == ROJA * DAMA;

							// si alguna roja o dama roja la rodea ver que pasa
							if (aDE || aIE || abIE || abDE) {
								if (aIE && abD)
									meComen = true;
								if (aDE && abI)
									meComen = true;
								if (abIED && aD)
									meComen = true;
								if (abDED && aI)
									meComen = true;
								if (meComen)
									salvos--;
							}
						}
					}
				}
			}
		}
		return salvos;
	}

	/**
	 * @param color
	 *            de una ficha
	 * @return distancia de todas las fichas de dicho color a la linea de
	 *         coronacion
	 */
	public static int distanciaALineaCoronacion(int[][] tab, int color) {
		int distancia = 0;
		if (esFichaRoja(color)) {
			for (int i = 0; i < 8; i++) {
				for (int j = 0; j < 8; j++) {
					if (tab[i][j] == ROJA)
						distancia += (7 - i);
				}
			}
		} else {
			for (int i = 0; i < 8; i++) {
				for (int j = 0; j < 8; j++) {
					if (tab[i][j] == NEGRA)
						distancia += i;
				}
			}
		}
		return distancia;
	}

	/**
	 * @param el
	 *            color de un jugador {@link int}
	 * @return {@link int} valoracion de acuerdo a la cantidad de fichas
	 *         proximas a coronarse damas del jugador
	 */
	public static int peonesProximosADamas(int[][] tablero, int color) {
		int cantFichas = 0;
		if (esFichaRoja(color)) {
			for (int i = 1; i < 3; i++)
				for (int j = 0; j < 8; j++) {
					if (tablero[i][j] == color)
						cantFichas++;
				}
			return 0;
		} else
			for (int i = 5; i < 7; i++)
				for (int j = 0; j < 8; j++) {
					if (tablero[i][j] == color)
						cantFichas++;
				}
		return cantFichas;
	}

	/**
	 * @param color
	 *            de una ficha (peon rojo, dama roja, peon negro, dama negra)
	 * @return cantidad de fichas de dicho color que se encuentran en la
	 *         diagonal principal
	 */
	public static int fichasEnDiagonalPrincipal(int[][] tab, int color) {
		int cantidad = 0;
		for (int i = 0; i < 8; i++) {
			if (tab[7 - i][i] == color)
				cantidad++;
		}
		return cantidad;
	}

	/**
	 * @param color
	 *            de una ficha (peon rojo, dama roja, peon negro, dama negra)
	 * @return cantidad de fichas de dicho color que se encuentran en la doble
	 *         diagonal
	 */
	public static int fichasEnDobleDiagonal(int[][] tab, int color) {
		int cantidad = 0;
		for (int i = 0; i < 7; i++) {
			if (tab[i][i + 1] == color)
				cantidad++;
			if (tab[i + 1][i] == color)
				cantidad++;
		}
		return cantidad;
	}

	/**
	 * @param color
	 *            de una ficha (peon rojo, dama roja, peon negro, dama negra)
	 * @return cantidad de fichas de dicho color que estan atacando (se
	 *         encuentran en las 3 filas mas cercanas a la coronacion)
	 */
	public static int fichasQueAtacan(int[][] tab, int color) {
		int cantidadPeones = 0;
		int cantidadDamas = 0;
		if (esFichaRoja(color)) {
			for (int i = 5; i < 8; i++) {
				for (int j = 0; j < 8; j++) {
					if (esFichaRoja(tab[i][j])) {
						if (color == ROJA)
							cantidadPeones++;
						else
							cantidadDamas++;
					}

				}
			}
		} else {
			for (int i = 0; i < 3; i++) {
				for (int j = 0; j < 8; j++) {
					if (!esFichaRoja(tab[i][j]) && tab[i][j] != 0) {
						if (color == NEGRA)
							cantidadPeones++;
						else
							cantidadDamas++;
					}
				}
			}
		}
		return cantidadPeones + cantidadDamas;
	}

	/**
	 * @param color
	 *            de una ficha (peon rojo, dama roja, peon negro, dama negra)
	 * @return cantidad de fichas de dicho color que estan defendiendo la linea
	 *         de coronacion, para que el enemigo no pueda formar damas (las 2
	 *         filas mas cercanas a la coronacion)
	 */
	public static int fichasQueDefienden(int[][] tab, int color) {
		int cantidadPeones = 0;
		int cantidadDamas = 0;
		if (esFichaRoja(color)) {
			for (int i = 0; i < 2; i++) {
				for (int j = 0; j < 8; j++) {
					if (esFichaRoja(tab[i][j])) {
						if (color == ROJA)
							cantidadPeones++;
						else
							cantidadDamas++;
					}

				}
			}
		} else {
			for (int i = 6; i < 8; i++) {
				for (int j = 0; j < 8; j++) {
					if (!esFichaRoja(tab[i][j]) && tab[i][j] != 0) {
						if (color == NEGRA)
							cantidadPeones++;
						else
							cantidadDamas++;
					}
				}
			}
		}
		return cantidadPeones + cantidadDamas;
	}

	/**
	 * @param tab
	 * @param color
	 *            de una ficha (peon rojo, dama roja, peon negro, dama negra)
	 * @return cantidad de fichas solitarias de dicho color en el tablero
	 *         (pueden ser comidas por una ficha enemiga)
	 */
	public static int fichasSolitarias(int[][] tab, int color) {
		int peonesSolit = 0;
		int damasSolit = 0;
		for (int i = 1; i < 7; i++) {
			for (int j = 1; j < 7; j++) {
				if (tab[i][j] == color) {
					if (tab[i - 1][j - 1] == 0 && tab[i - 1][j + 1] == 0
							&& tab[i + 1][j - 1] == 0 && tab[i + 1][j + 1] == 0) {
						if (color == ROJA || color == NEGRA)
							peonesSolit++;
						else
							damasSolit++;
					}
				}
			}

		}
		return peonesSolit + damasSolit;
	}

	/**
	 * @param tab
	 * @param color
	 * @return cantidad de campos libres en la linea de coronacion del jugador
	 *         del color pasado como parametro
	 */
	public static int camposLibresEnLineaCoronacion(int[][] tab, int color) {
		int cantidadCampos = 0;
		if (esFichaRoja(color)) {
			for (int i = 1; i < 8; i += 2) {
				if (tab[0][i] == 0)
					cantidadCampos++;
			}
		} else {
			for (int i = 0; i < 8; i += 2) {
				if (tab[7][i] == 0)
					cantidadCampos++;
			}
		}
		return cantidadCampos;
	}

	/**
	 * @param tablero
	 * @param color
	 *            de una ficha (peon rojo, dama roja, peon negro, dama negra)
	 * @return cantidad de fichas (del jugador de color pasado como parametro)
	 *         en las dos lineas del centro del tablero
	 */
	public static int cantFichasEnCentro(int[][] tablero, int color) {
		int cantFichas = 0;
		for (int i = 3; i < 5; i++) {
			for (int j = 0; j < 8; j++) {
				if (tablero[i][j] == color)
					cantFichas++;
			}
		}
		return cantFichas;
	}

	/**
	 * @param tablero
	 * @param color
	 *            de un jugador
	 * @return cantidad de campos vacios que tienen al menos 3 fichas adyacentes
	 *         del color pasado como parametro
	 */
	public static int camposVaciosRodeadosPorColor(int[][] tablero, int color) {
		int cantCampos = 0;
		int cantidadFichasAdy;
		int ArrIz, ArrDer, AbIz, AbDer, DerArr, DerAb, IzArr, IzAb, posAct;
		for (int i = 1; i < 7; i++) {
			for (int j = 1; j < 7; j++) {
				cantidadFichasAdy = 0;
				ArrIz = tablero[i - 1][j - 1];
				ArrDer = tablero[i - 1][j + 1];
				AbIz = tablero[i + 1][j - 1];
				AbDer = tablero[i + 1][j + 1];
				posAct = tablero[i][j];
				if (posAct == 0) {
					if (esFichaRoja(color)) {
						if (esFichaRoja(ArrIz))
							cantidadFichasAdy++;
						if (esFichaRoja(ArrDer))
							cantidadFichasAdy++;
						if (esFichaRoja(AbIz))
							cantidadFichasAdy++;
						if (esFichaRoja(AbDer))
							cantidadFichasAdy++;
					} else {
						if (!esFichaRoja(ArrIz) && ArrIz != 0)
							cantidadFichasAdy++;
						if (!esFichaRoja(ArrDer) && ArrDer != 0)
							cantidadFichasAdy++;
						if (!esFichaRoja(AbIz) && AbIz != 0)
							cantidadFichasAdy++;
						if (!esFichaRoja(AbDer) && AbDer != 0)
							cantidadFichasAdy++;
					}
					// si el campo esta rodeado por al menos 3 fichas del color
					// pasado como parametro, encontre uno mas
					if (cantidadFichasAdy >= 3)
						cantCampos++;
				}
			}
		}
		// ver si se puede mejorar el codigo desde aca hasta que termina el metodo!
		// orilla superior
		for (int i = 1; i < 8; i += 2) {
			cantidadFichasAdy = 0;
			AbIz = tablero[1][i - 1];
			AbDer = 0;
			if (i < 7)
				AbDer = tablero[1][i + 1];
			posAct = tablero[0][i];
			if (posAct == 0) {
				if (esFichaRoja(color)) {
					if (esFichaRoja(AbIz))
						cantidadFichasAdy++;
					if (esFichaRoja(AbDer))
						cantidadFichasAdy++;
				} else {
					if (!esFichaRoja(AbIz) && AbIz != 0)
						cantidadFichasAdy++;
					if (!esFichaRoja(AbDer) && AbDer != 0)
						cantidadFichasAdy++;
				}
				// si el campo esta rodeado por al menos 1 fichas del color
				// pasado como parametro, encontre uno mas
				if (cantidadFichasAdy >= 1)
					cantCampos++;
			}
		}

		// orilla inferior
		for (int i = 0; i < 7; i += 2) {
			cantidadFichasAdy = 0;
			ArrDer = tablero[6][i + 1];
			ArrIz = 0;
			if (i > 0)
				ArrIz = tablero[6][i - 1];
			posAct = tablero[7][i];
			if (posAct == 0) {
				if (esFichaRoja(color)) {
					if (esFichaRoja(ArrDer))
						cantidadFichasAdy++;
					if (esFichaRoja(ArrIz))
						cantidadFichasAdy++;
				} else {
					if (!esFichaRoja(ArrDer) && ArrDer != 0)
						cantidadFichasAdy++;
					if (!esFichaRoja(ArrIz) && ArrIz != 0)
						cantidadFichasAdy++;
				}
				// si el campo esta rodeado por al menos 1 fichas del color
				// pasado como parametro, encontre uno mas
				if (cantidadFichasAdy >= 1)
					cantCampos++;
			}
		}

		// orilla lateral izquierda
		for (int i = 1; i < 8; i += 2) {
			cantidadFichasAdy = 0;
			DerArr = tablero[i - 1][1];
			DerAb = 0;
			if (i < 7)
				DerAb = tablero[i + 1][1];
			posAct = tablero[i][0];
			if (posAct == 0) {
				if (esFichaRoja(color)) {
					if (esFichaRoja(DerArr))
						cantidadFichasAdy++;
					if (esFichaRoja(DerAb))
						cantidadFichasAdy++;
				} else {
					if (!esFichaRoja(DerArr) && DerArr != 0)
						cantidadFichasAdy++;
					if (!esFichaRoja(DerAb) && DerAb != 0)
						cantidadFichasAdy++;
				}
				// si el campo esta rodeado por al menos 1 fichas del color
				// pasado como parametro, encontre uno mas
				if (cantidadFichasAdy >= 1)
					cantCampos++;
			}
		}

		// orilla lateral derecha
		for (int i = 0; i < 7; i += 2) {
			cantidadFichasAdy = 0;
			IzAb = tablero[i + 1][6];
			IzArr = 0;
			if (i > 0)
				IzArr = tablero[i - 1][6];
			posAct = tablero[i][7];
			if (posAct == 0) {
				if (esFichaRoja(color)) {
					if (esFichaRoja(IzAb))
						cantidadFichasAdy++;
					if (esFichaRoja(IzArr))
						cantidadFichasAdy++;
				} else {
					if (!esFichaRoja(IzAb) && IzArr != 0)
						cantidadFichasAdy++;
					if (!esFichaRoja(IzArr) && IzArr != 0)
						cantidadFichasAdy++;
				}
				// si el campo esta rodeado por al menos 1 fichas del color
				// pasado como parametro, encontre uno mas
				if (cantidadFichasAdy >= 1)
					cantCampos++;
			}
		}

		return cantCampos;
	}

	/**
	 * @param color
	 * @return si el color pertenece a una ficha roja o dama roja
	 */
	private static boolean esFichaRoja(int color) {
		return ((color == ROJA || color == ROJA * DAMA));
	}

	/**
	 * @param t
	 *            {{@link int[][]}
	 * @param color
	 *            t{{@link int}
	 * @return t {@link int} Cantidad de fichas que tengo posocionadas en las
	 *         esquinas, difrencia el color en NEGRAS , DAMAS NEGRAS, ROJAS,
	 *         DAMAS ROJAS
	 */
	public static int fichasEnEsquinas(int[][] t, int color) {
		int cantidad = 0;
		if (t[0][7] == color)
			cantidad++;
		if (t[7][0] == color)
			cantidad++;

		return cantidad;
	}

	/**
	 * @param color
	 * @param tablero
	 * @return cantidad de fichas que bloquean la linea de coronacion del
	 *         jugador de color pasado como parametro
	 */
	public static int bloqueoParaDamas(int color, int[][] tablero) {
		int cuantasBloquean = 0;
		if (esFichaRoja(color)) {
			for (int i = 1; i < 8; i += 2) {
				if (esFichaRoja(tablero[0][i]))
					cuantasBloquean++;
			}
		} else {
			for (int i = 0; i < 8; i += 2) {
				if (!esFichaRoja(tablero[7][i]) && tablero[7][i] != 0)
					cuantasBloquean++;
			}
		}
		return cuantasBloquean;
	}

}
